﻿namespace CommonData.Log
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Threading;

    public class Log : IDisposable
    {
        private static Queue<LogMessage> logMessages;
        private static LogType logtype;
        private static string path;
        private static bool state;
        private static DateTime time;
        private static StreamWriter writer;

        public Log() : this(@".\", LogType.Daily)
        {
        }

        public Log(LogType t) : this(@".\", t)
        {
        }

        public Log(string filepath, LogType t)
        {
            if (logMessages == null)
            {
                state = true;
                path = filepath;
                logtype = t;
                this.FileOpen();
                logMessages = new Queue<LogMessage>();
                new Thread(new ThreadStart(this.Work)).Start();
            }
        }

        public void Dispose()
        {
            state = false;
            GC.SuppressFinalize(this);
        }

        private void FileClose()
        {
            if (writer != null)
            {
                writer.Flush();
                writer.Close();
                writer.Dispose();
                writer = null;
            }
        }

        private void FileOpen()
        {
            writer = new StreamWriter(path + this.GetFileName(), true, Encoding.Default);
        }

        private string GetFileName()
        {
            DateTime now = DateTime.Now;
            string format = "";
            switch (logtype)
            {
                case LogType.Daily:
                    time = new DateTime(now.Year, now.Month, now.Day);
                    time = time.AddDays(1.0);
                    format = "yyyyMMdd'.log'";
                    break;

                case LogType.Weekly:
                    time = new DateTime(now.Year, now.Month, now.Day);
                    time = time.AddDays(7.0);
                    format = "yyyyMMdd'.log'";
                    break;

                case LogType.Monthly:
                    time = new DateTime(now.Year, now.Month, 1);
                    time = time.AddMonths(1);
                    format = "yyyyMM'.log'";
                    break;

                case LogType.Annually:
                    time = new DateTime(now.Year, 1, 1);
                    time = time.AddYears(1);
                    format = "yyyy'.log'";
                    break;
            }
            return now.ToString(format);
        }

        private void Work()
        {
            while (true)
            {
                if (logMessages.Count > 0)
                {
                    LogMessage message = null;
                    lock (logMessages)
                    {
                        message = logMessages.Dequeue();
                    }
                    if (message != null)
                    {
                        this.WriteLogMessage(message);
                    }
                }
                else if (state)
                {
                    Thread.Sleep(1);
                }
                else
                {
                    this.FileClose();
                }
            }
        }

        public void Write(LogMessage message)
        {
            if (logMessages != null)
            {
                lock (logMessages)
                {
                    logMessages.Enqueue(message);
                }
            }
        }

        public void Write(Exception e, MessageType type)
        {
            this.Write(new LogMessage(e.Message, type));
        }

        public void Write(string text, MessageType type)
        {
            this.Write(new LogMessage(text, type));
        }

        public void Write(DateTime now, string text, MessageType type)
        {
            this.Write(new LogMessage(now, text, type));
        }

        private void WriteLogMessage(LogMessage message)
        {
            try
            {
                if (writer == null)
                {
                    this.FileOpen();
                }
                else
                {
                    if (DateTime.Now >= time)
                    {
                        this.FileClose();
                        this.FileOpen();
                    }
                    writer.Write(message.Time);
                    writer.Write("\t");
                    writer.Write(message.Type);
                    writer.Write("\t\r\n");
                    writer.Write(message.Content);
                    writer.Write("\r\n\r\n");
                    writer.Flush();
                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
        }
    }
}

